﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Net;

namespace LiveNet.Silverlight
{
    public sealed partial class LiveMedia : LiveNetBase<LiveMediaRequestCreator, LiveMediaAuthenticationDetails>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LiveMedia"/> class.
        /// </summary>
        /// <param name="accountId">The account id.</param>
        /// <param name="accountKey">The account key.</param>
        /// <example>
        /// <code>
        /// // Calls the LiveMedia Service
        /// // Make sure you use LiveNet.Silverlight;
        /// 
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// </code>
        /// </example>
        public LiveMedia(string accountId, string accountKey)
            : base(new LiveMediaAuthenticationDetails(accountId, accountKey),
                   new Uri(string.Format("https://silverlight.services.live.com/{0}", accountId)))
        {
        }

        #region Public Methods
        /// <summary>
        /// Lists the file sets.
        /// </summary>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// // Return a list of the File Sets that you have in your account
        /// MediaFileSet[] sets = m_liveMedia.ListFileSets();
        /// 
        /// // Loop through and list all the set names
        /// foreach(MediaFileSet set in sets)
        /// {
        ///     Console.WriteLine(set.Name);
        /// }
        /// </code>
        /// </example>
        public MediaFileSet[] ListFileSets()
        {
            List<MediaFileSet> result = new List<MediaFileSet>();

            MakeGetRequest(RootPath, delegate(Stream stream)
                                         {
                                             ParseGetRequest(stream, string.Empty, delegate(XmlNode xmlnode)
                                                                                       {
                                                                                           result.Add(
                                                                                               ParseFileSet(xmlnode));
                                                                                       });
                                         });
                        
            return result.ToArray();
        }

        /// <summary>
        /// Gets the file set.
        /// </summary>
        /// <param name="appName">Name of the app.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// string myApp = "My App Name";
        /// 
        /// MediaFileSet mySet = m_liveMedia.GetFileSet(myApp);
        /// 
        /// // Display the Set name
        /// if(mySet != null)
        /// {
        ///     Console.WriteLine(mySet.Name);
        /// }
        /// </code>
        /// </example>
        public MediaFileSet GetFileSet(string appName)
        {
            MediaFileSet result = null;
            MakeGetRequest(RootPath, delegate(Stream stream)
                                         {
                                             ParseGetRequest(stream, appName, delegate(XmlNode xmlnode)
                                                                                  {
                                                                                      result = ParseFileSet(xmlnode);
                                                                                  });
                                         });
            return result;
        }

        /// <summary>
        /// Gets the file set.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// Uri url = new Uri(string.Format("https://silverlight.services.live.com/{0}/{1}", 
        ///                                 m_liveMedia.AccountID, "myApp"));
        /// 
        /// MediaFileSet mySet = m_liveMedia.GetFileSet(url);
        /// 
        /// // Display the Set name
        /// if(mySet != null)
        /// {
        ///     Console.WriteLine(mySet.Name);
        /// }
        /// </code>
        /// </example>
        public MediaFileSet GetFileSet(Uri url)
        {
            string appName = url.ToString();
            appName = appName.Replace(RootPath + "/", "");

            return GetFileSet(appName);
        }

        /// <summary>
        /// Adds the file set.
        /// </summary>
        /// <param name="zipFile">The zipfile.</param>
        /// <param name="applicationName">Name of the app.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// string zipfile = @"c:\mynewapp.zip";
        /// string appname = "My New App";
        /// 
        /// // Add a new File Set (application).
        /// // This *MUST* be a zip file.
        /// MediaFileSet newApp = m_liveMedia.AddFileSet(zipfile, appname);
        /// </code>
        /// </example>
        public MediaFileSet AddFileSet(string zipFile, string applicationName)
        {
            if (string.IsNullOrEmpty(zipFile))
            {
                throw new ArgumentNullException("applicationName");
            }

            if (!File.Exists(zipFile))
            {
                throw new FileNotFoundException("The zip file could not be found.", zipFile);
            }
            else
            {
                if (!zipFile.EndsWith(".zip"))
                {
                    throw new LiveNetException("Not a zip file");
                }
            }

            using (Stream s = File.Open(zipFile, FileMode.Open))
            {
                return AddFileSet(s, applicationName);
            }
        }

        /// <summary>
        /// Adds the file set.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <param name="applicationName">Name of the app.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// string zipfile = @"c:\mynewapp.zip";
        /// string appname = "My New App";
        /// Stream file = File.Open(zipfile, FileMode.Open);
        /// 
        /// // Add a new File Set (application).
        /// MediaFileSet newApp = m_liveMedia.AddFileSet(file, appname);
        /// </code>
        /// </example>
        public MediaFileSet AddFileSet(Stream file, string applicationName)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            if (string.IsNullOrEmpty(applicationName))
            {
                throw new ArgumentNullException("applicationName");
            }

            MediaFileSet result = null;
            Uri url = new Uri(string.Format("{0}/{1}", RootPath, applicationName));

            // Server doesn't allow incremental changes, so Application must be deleted and readded
            MakeDeleteRequest(url, true);
            MakePutRequest(url, file, delegate
                                          {
                                              result = GetFileSet(url);
                                          });

            return result;            
        }

        /// <summary>
        /// Deletes the file set.
        /// </summary>
        /// <param name="applicationName">Name of the app.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// string appname = "My New App";
        /// if(m_liveMedia.DeleteFileSet(appname))
        /// {
        ///     Console.WriteLine(string.Format("\"{0}\" has been deleted.", appname));
        /// }
        /// </code>
        /// </example>
        public bool DeleteFileSet(string applicationName)
        {
            Uri url = new Uri(string.Format("{0}/{1}", RootPath, applicationName));

            return MakeDeleteRequest(url, false);
        }

        /// <summary>
        /// Deletes the file set.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        /// <example>
        /// <code>
        /// // Create your LiveMedia instance
        /// LiveMedia m_liveMedia = new LiveMedia("AccountID", "AccountKey");
        /// 
        /// string appname = "myApp";
        /// Uri url = new Uri(string.Format("https://silverlight.services.live.com/{0}/{1}", 
        ///                                 m_liveMedia.AccountID, appname));
        ///                                 
        /// if(m_liveMedia.DeleteFileSet(url))
        /// {
        ///     Console.WriteLine(string.Format("\"{0}\" has been deleted.", appname));
        /// }
        /// </code>
        /// </example>
        public bool DeleteFileSet(Uri url)
        {
            return MakeDeleteRequest(url, false);
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the Account ID.
        /// </summary>
        /// <value>The account Id.</value>
        public string AccountId
        {
            get { return AuthenticationDetails.AccountId; }
        }
        #endregion

        #region Private Methods
        internal MediaFile[] GetFiles(MediaFileSet parent)
        {
            List<MediaFile> result = new List<MediaFile>();
            MakeGetRequest(parent.FileSetUrl, delegate(Stream stream)
                                                  {
                                                      ParseGetFiles(stream, delegate(XmlNode xmlnode)
                                                                                {
                                                                                    result.Add(
                                                                                        ParseFiles(xmlnode, parent));
                                                                                });
                                                  });
            return result.ToArray();
        }

        internal Stream GetFileStream(Uri url, string mimeType)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            
            if (string.IsNullOrEmpty(mimeType))
            {
                throw new ArgumentNullException("mimeType");
            }
            
            Stream result;
            HttpWebRequest request = BuildRequest(url, "GET");
            request.ContentType = mimeType;

            try
            {
                using (HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse())
                {
                    result = httpResponse.GetResponseStream();
                }
            }
            catch (WebException ex)
            {
                throw new LiveNetRequestException(ex.Message, ex);
            }

            return result;
        }
        #endregion
    }
}
